#pragma once
#include "timeout_exception.hpp"
#include <vector>
#include <unordered_map>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <chrono>
#include <functional>
#include <iostream>


#include <chrono>
#include <ctime>
#include <iomanip>


namespace timeout_manager {

/**
 * 时间轮定时器
 * 
 * 工作原理：
 * 1. 时间轮是一个固定大小的数组（比如3600个槽，代表3600秒）
 * 2. 每个槽存储在该时刻应该触发的定时任务
 * 3. 时间指针每隔固定间隔（比如1秒）向前移动一个槽
 * 4. 当指针指向某个槽时，触发该槽中的所有任务
 */
class TimerWheel {
public:
    using TimePoint = std::chrono::steady_clock::time_point;
    using Duration = std::chrono::milliseconds;
    using TimeoutCallback = std::function<void()>;
    
    /**
     * 定时任务结构
     */
    struct TimerTask {
        uint64_t id;                 // 任务唯一ID
        TimePoint expireTime;        // 过期时间点
        TimeoutCallback callback;    // 超时时要执行的回调函数
        
        TimerTask(uint64_t taskId, TimePoint expire, TimeoutCallback cb)
            : id(taskId), expireTime(expire), callback(std::move(cb)) {}
    };
    
    /**
     * 构造函数
     * @param wheelSize 时间轮大小（槽的数量）
     * @param tickDuration 时间轮转动间隔（每个槽代表的时间）
     */
    TimerWheel(size_t wheelSize = 3600, Duration tickDuration = std::chrono::milliseconds(1000));
    
    /**
     * 析构函数
     */
    ~TimerWheel();
    
    /**
     * 添加定时任务
     * @param taskId 任务ID
     * @param timeout 超时时间（从现在开始多久后超时）
     * @param callback 超时回调函数
     */
    void addTimer(uint64_t taskId, Duration timeout, TimeoutCallback callback);
    
    /**
     * 移除定时任务
     * @param taskId 要移除的任务ID
     * @return 是否成功移除
     */
    bool removeTimer(uint64_t taskId);
    
    /**
     * 启动时间轮
     */
    void start();
    
    /**
     * 停止时间轮
     */
    void stop();
    
    /**
     * 获取统计信息
     */
    struct Statistics {
        size_t totalSlots;      // 总槽数
        size_t activeTimers;    // 活跃定时器数量
        size_t currentSlot;     // 当前槽位置
    };
    
    Statistics getStatistics() const;

    /**
     * 调试函数：打印所有槽位中的任务信息
     * @param showEmptySlots 是否显示空槽位，默认false
     * @param detailLevel 详细级别：0=简单，1=详细，2=超详细
     */
    void printAllSlots(bool showEmptySlots = false, int detailLevel = 1) const;
    
    /**
     * 打印指定槽位的任务信息
     */
    void printSlot(size_t slot) const;
    
private:
    /**
     * 时间轮转动的线程函数
     */
    void timerThreadFunc();
    
    /**
     * 处理当前槽位的过期任务
     * @param slot 槽位索引
     */
    void processExpiredTasks(size_t slot);
    
    /**
     * 根据过期时间计算应该放在哪个槽位
     * @param expireTime 过期时间点
     * @return 槽位索引
     */
    size_t getSlot(TimePoint expireTime) const;
    
    const size_t wheelSize_;           // 时间轮大小
    const Duration tickDuration_;     // 每个槽的时间间隔
    
    // 时间轮：每个槽位存储一个任务列表
    std::vector<std::vector<TimerTask>> wheel_;
    
    // 快速查找表：任务ID -> 槽位索引
    std::unordered_map<uint64_t, size_t> taskSlotMap_;
    
    std::thread timerThread_;         // 时间轮转动线程
    std::atomic<bool> running_;       // 运行状态标志
    mutable std::mutex wheelMutex_;   // 保护时间轮的互斥锁
    std::condition_variable stopCondition_; // 用于优雅停止
    
    TimePoint startTime_;             // 时间轮启动时间
    std::atomic<size_t> currentSlot_; // 当前时间指针位置



    void printCurrentTime() {
        auto now = std::chrono::system_clock::now();
        auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
        auto time_t_now = std::chrono::system_clock::to_time_t(now);
        std::tm* now_tm = std::localtime(&time_t_now);

        std::cout << std::put_time(now_tm, "%Y-%m-%d %H:%M:%S");
        std::cout << '.' << std::setw(3) << std::setfill('0') << milliseconds.count() << '\n';
        }
    
    



     /**
     * 打印单个任务的详细信息
     */
    void printTaskInfo(const TimerTask& task, 
                      std::chrono::steady_clock::time_point now,
                      std::chrono::milliseconds timeSinceStart,
                      int detailLevel) const;
    
    /**
     * 获取任务当前所在的槽位
     */
    size_t getCurrentSlotForTask(uint64_t taskId) const;
};

} // namespace timeout_manager